package org.dei.perla.sys.core;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.dei.perla.sys.core.exception.AgentRegisrtyException;
import org.dei.perla.sys.utils.TablePrettyPrinter;
import org.dei.perla.sys.utils.TablePrettyPrinterException;
import org.dei.perla.utils.Pair;
public class AgentRegistry extends DefaultAgent<Object, Object> {

	private static int freeId = 0;
	@SuppressWarnings("unchecked")
	private static Map<DefaultAgent, Pair<AgentState, Integer>> registry = new HashMap<DefaultAgent,  Pair<AgentState, Integer>>();

	protected AgentRegistry(String parName) throws AgentRegisrtyException {
		super(parName);
		this.subscribe();
	}

	@Override
	protected void loop() {

	}
	
	@SuppressWarnings("unchecked")
	private ArrayList<DefaultAgent> getAgentListWithState(AgentState state){
		synchronized (registry) {
			ArrayList<DefaultAgent> subList = new ArrayList<DefaultAgent>();
			for (DefaultAgent agent: registry.keySet()) {
				if(registry.get(agent).getFirst() == state)
					subList.add(agent);
			}
			return subList;			
		}
	}
	
	@SuppressWarnings("unchecked")
	public ArrayList<DefaultAgent> getRunningAgentList(){
		return this.getAgentListWithState(AgentState.RUNNING);
	}
	
	@SuppressWarnings("unchecked")
	public ArrayList<DefaultAgent> getStoppedAgentList(){
		return this.getAgentListWithState(AgentState.STOPPED);
	}
	
	@SuppressWarnings("unchecked")
	public ArrayList<DefaultAgent> getDeadAgentList(){
		return this.getAgentListWithState(AgentState.DEAD);
	}
	
	@SuppressWarnings("unchecked")
	public static ArrayList<String[]> getAgentsStatus(){
		synchronized (registry) {
			ArrayList<String[]> subList = new ArrayList<String[]>();
			String head[] = {"Agent ID", "Agent Name", "Agent Status", "Birth", "Death"};
			subList.add(head);
			for (Entry<DefaultAgent, Pair<AgentState, Integer>> entry: registry.entrySet()) {
				String ID = entry.getValue().getSecond().toString();
				String name = entry.getKey().getName();
				String status = entry.getValue().getFirst().toString();
				String birthDate = new Date(entry.getKey().getBirthDate()).toString();
				String deathDate = "--";
				if(entry.getKey().getDeathDate() != -1L)
					deathDate = new Date(entry.getKey().getDeathDate()).toString();				
				String []record = {ID, name, status, birthDate, deathDate};
				subList.add(record);
			}
			return subList;			
		}
	}

	@SuppressWarnings("unchecked")
	public static AgentState getAgentStatus(DefaultAgent agent){
		synchronized (registry) {
			if(registry.containsKey(agent))
				return registry.get(agent).getFirst();
			return AgentState.NOT_PRESENT;
		}
	}
	
	public static void printAgentStatus(){
		try {
			ArrayList<String[]> status = new ArrayList<String[]>();
			String head[] = {"Agent Name", "Agent Status", "Agent ID"};
			status.add(head);
			status.addAll(getAgentsStatus());
			TablePrettyPrinter.print("AgentRegistry", status, System.out);
		} catch (TablePrettyPrinterException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void respawn() {
		AgentState state = registry.get(this).getFirst();
		switch(state) {
			case DEAD:{
				new Thread(this).start();
			}
			case STOPPED:
			case RUNNING:
			default:
				break;
		}
	}
	
	@SuppressWarnings("unchecked")
	public static void changeState(DefaultAgent agent, AgentState currentState) throws AgentRegisrtyException{
		synchronized (registry) {
			if(registry.containsKey(agent)){
				Integer id = registry.get(agent).getSecond(); 
				registry.put(agent, new Pair<AgentState, Integer>(currentState, id));
			}
			else throw new AgentRegisrtyException();
		}
	}

	@Override
	public ArrayList<String[]> inspect() {
		return AgentRegistry.getAgentsStatus();
	}

	@SuppressWarnings("unchecked")
	public static DefaultAgent getAgent(int id) {
		Set<DefaultAgent> set = registry.keySet();
		for (Iterator<DefaultAgent> iterator = set.iterator(); iterator.hasNext();) {
			DefaultAgent defaultAgent = iterator.next();
			if(defaultAgent.getID() == id)
				return defaultAgent;
		}
		return null;
	}

	public static int getFreeId() {
		int freeId = AgentRegistry.freeId;
		AgentRegistry.freeId++;
		return freeId;
	}

	@SuppressWarnings("unchecked")
	static void addToRegistry(DefaultAgent defaultAgent, AgentState stopped, int idAgent) throws AgentRegisrtyException {
		if(registry.containsKey(defaultAgent))
			throw new AgentRegisrtyException();
		registry.put(defaultAgent, new Pair<AgentState, Integer>(stopped, idAgent));
		
	}
	
	
}
